#import "CoverViewController.h"

#define CVC_VIEW_TAG		999

// *********************************************
// Extending UIView to reveal its heartbeat methods
// 
@interface UIView (extended)
- (void) startHeartbeat: (SEL) aSelector inRunLoopMode: (id) mode;
- (void) stopHeartbeat: (SEL) aSelector;
@end


// *********************************************
// The FlipView layer prevents touches from reaching the Coverflow layer behind it.
//
@interface FlipView : UIView
{
	UILabel *flipLabel;
}
@property (nonatomic, retain)		UILabel *flipLabel;
@end

@implementation FlipView
@synthesize flipLabel;

- (FlipView *) initWithFrame: (CGRect) aRect
{
	self = [super initWithFrame:aRect];
	
	// Add the flip label that shows the name and hex value
	self.flipLabel = [[UILabel alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 480.0f, 480.0f)];
	self.flipLabel.textColor = [UIColor whiteColor];
	self.flipLabel.backgroundColor = [UIColor clearColor];
	self.flipLabel.textAlignment = UITextAlignmentCenter;
	self.flipLabel.font = [UIFont boldSystemFontOfSize:24.0f];
	self.flipLabel.userInteractionEnabled = NO;

	[self.flipLabel setNumberOfLines:3];
	[self addSubview:self.flipLabel];
	[self.flipLabel release];
	
	return self;
}

- (void) setText: (NSString *) theText
{
	self.flipLabel.text = theText;
}

// When touched, remove the label and unflip the swatch
- (void) touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event
{
	[self removeFromSuperview];
	[(CoverFlowView *)[[[UIApplication sharedApplication] keyWindow] viewWithTag:CVC_VIEW_TAG] flipSelectedCover];
}

- (void) dealloc
{
	[self.flipLabel release];
	[super dealloc];
}
@end


// *********************************************
// IMAGE UTILITY FUNCTIONS
//

// MyCreateBitmapContext: Source based on Apple Sample Code
CGContextRef MyCreateBitmapContext (int pixelsWide, int pixelsHigh)
{
    CGContextRef    context = NULL;
    CGColorSpaceRef colorSpace;
    void *          bitmapData;
    int             bitmapByteCount;
    int             bitmapBytesPerRow;
	
    bitmapBytesPerRow   = (pixelsWide * 4);
    bitmapByteCount     = (bitmapBytesPerRow * pixelsHigh);
	
    colorSpace = CGColorSpaceCreateDeviceRGB();
    bitmapData = malloc( bitmapByteCount );
    if (bitmapData == NULL)
    {
        fprintf (stderr, "Memory not allocated!");
        return NULL;
    }
    context = CGBitmapContextCreate (bitmapData, pixelsWide, pixelsHigh, 8, bitmapBytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast);
    if (context== NULL)
    {
        free (bitmapData);
        fprintf (stderr, "Context not created!");
        return NULL;
    }
    CGColorSpaceRelease( colorSpace );
	
    return context;
}

// Convert a 6-character hex color to a UIColor object
CGColorRef getColor(NSString *hexColor)
{
	unsigned int red, green, blue;
	NSRange range;
	range.length = 2;
	
	range.location = 0; 
	[[NSScanner scannerWithString:[hexColor substringWithRange:range]] scanHexInt:&red];
	range.location = 2; 
	[[NSScanner scannerWithString:[hexColor substringWithRange:range]] scanHexInt:&green];
	range.location = 4; 
	[[NSScanner scannerWithString:[hexColor substringWithRange:range]] scanHexInt:&blue];	
	
	return [[UIColor colorWithRed:(float)(red/255.0f) green:(float)(green/255.0f) blue:(float)(blue/255.0f) alpha:1.0f] CGColor];
}

// Create the target color swatch
id createImage(NSString *crayonColor)
{
	CGRect aRect = CGRectMake(0.0f, 0.0f, 200.0f, 200.0f);
	CGContextRef context = MyCreateBitmapContext(200, 200);
	CGContextClearRect(context, aRect);
	
	CGContextSetFillColorWithColor(context, [[UIColor colorWithRed:1.0f green:1.0f blue:1.0f alpha:0.25f] CGColor]);
	CGContextFillEllipseInRect(context, aRect);
	
	CGContextSetFillColorWithColor(context, getColor(crayonColor));
	CGContextFillEllipseInRect(context, CGRectInset(aRect, 40.0f, 40.0f));
	
	CGImageRef myRef = CGBitmapContextCreateImage (context);
	free(CGBitmapContextGetData(context));
	CGContextRelease(context);
	
	return [UIImage imageWithCGImage:myRef];
}

// *********************************************
// Coverflow View Controller
//
@implementation CoverViewController

@synthesize cfView;
@synthesize covers;
@synthesize titles;
@synthesize colorDict;
@synthesize whichItem;

- (CoverViewController *) init
{
	if (!(self = [super init])) return self;
	
	NSArray *crayons = [[NSString stringWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"crayons" ofType:@"txt"] encoding: NSUTF8StringEncoding error:nil] componentsSeparatedByString:@"\n"];
	self.covers = [[NSMutableArray alloc] init];
	self.titles = [[NSMutableArray alloc] init];
	self.colorDict = [[NSMutableDictionary alloc] init];
	
	// Create the title and cover arrays
	for (NSString *crayon in crayons)
	{
		NSArray *theCrayon = [crayon componentsSeparatedByString:@" #"];
		if ([theCrayon count] != 2) continue;
		[self.titles addObject:[theCrayon objectAtIndex:0]];
		[self.covers addObject:createImage([theCrayon objectAtIndex:1])];
		[self.colorDict setObject:[theCrayon objectAtIndex:1] forKey:[theCrayon objectAtIndex:0]];
	}
	
	// Create the flip object
	CGRect fliprect = CGRectMake(0.0f, 0.0f, 480.0f, 480.0f);
	flippedView = [[FlipView alloc] initWithFrame:fliprect];
	[flippedView setTransform:CGAffineTransformMakeRotation(3.141592f / 2.0f)];
	[flippedView setUserInteractionEnabled:YES];
	
	// Initialize 
	self.cfView = [[CoverFlowView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame] andCount:[self.titles count]];
	[self.cfView setUserInteractionEnabled:YES];
	[self.cfView setHost:self];
	
	// Finish setting up the cover flow layer
	self.whichItem = [self.titles count] / 2;
	[self.cfView.cfLayer selectCoverAtIndex:self.whichItem];
	[self.cfView.cfLayer setDelegate:self];
	
	selector = NULL;
	target = NULL;
	
	return self;
}	

// *********************************************
// Coverflow delegate methods
//
- (void) coverFlow: (id) coverFlow selectionDidChange: (int) index
{
	self.whichItem = index;
	[self.cfView.label setText:[self.titles objectAtIndex:index]];
}

// Detect the end of the flip -- both on reveal and hide
- (void) coverFlowFlipDidEnd: (UICoverFlowLayer *)coverFlow 
{
	if (flipOut)
		[[[UIApplication sharedApplication] keyWindow] addSubview:flippedView];
	else
		[flippedView removeFromSuperview];
}


// *********************************************
// Coverflow datasource methods
//

- (void) coverFlow:(id)coverFlow requestImageAtIndex: (int)index quality: (int)quality
{
	UIImage *whichImg = [self.covers objectAtIndex:index];
	[coverFlow setImage:[whichImg CGImage]  atIndex:index type:quality];
}

// Return a flip layer, one that preferably integrates into the flip presentation
- (id) coverFlow: (UICoverFlowLayer *)coverFlow requestFlipLayerAtIndex: (int) index
{
	if (flipOut) [flippedView removeFromSuperview];
	flipOut = !flipOut;
	
	// Prepare the flip text
	[flippedView setText:[NSString stringWithFormat:@"%@\n%@", [self.titles objectAtIndex:index], [self.colorDict objectForKey:[self.titles objectAtIndex:index]]]];
	
	// Flip with a simple blank square
	UIView *view = [[[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 140.0f, 140.0f)] autorelease];
	[view setBackgroundColor:[UIColor clearColor]];
	
	return [view layer];
}

// *********************************************
// Utility methods
//

- (int) selectedItem
{
	return self.whichItem;
}

- (void) start
{
	[self.cfView startHeartbeat: @selector(tick) inRunLoopMode: (id)kCFRunLoopDefaultMode];
	[self.cfView.cfLayer transitionIn:1.0f];
}

- (void) stop
{
	[self.cfView stopHeartbeat: @selector(tick)];
}

- (void) loadView
{
	[super loadView];
	self.view = self.cfView;
	[self start];
}

- (void) dealloc
{
	if (target) [target release];
	if (flippedView) [flippedView release];
	[self.cfView  release];
	[self.covers release];
	[self.titles release];
	[self.colorDict release];
	[super dealloc];
}

// *********************************************
// Callback method for double tap
//

- (void) doubleTapCallback
{
}

@end
